﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "WallTag.h"
#include "IElementParentReporter.h"
#include "IGenericElement.h"
#include "IDocument.h"
#include "DbObjectUtils.h"
#include "IElementBasicInformation.h"
#include "CategoryDefine.h"
#include "IRegenerator.h"
#include "IRegeneratorDataIdCreator.h"
#include "ElementId.h"
#include "TaggingWall.h"
#include "../WallModule/Wall/Wall.h"
#include "../UIPlatform/CategoryDefine.h"
//组件
#include "WallTagPositionPoints.h"
#include "WallTagRegenerationComponent.h"
//图形表示
#include "IElementModelShape.h"
#include "IGraphicsElementShape.h"
#include "IGraphicsText.h"
#include "IGraphicsBRepBody.h"
#include "IGraphicsPolyCurve.h"
#include "IGraphicsNodeGroup.h"
#include "IGraphicsZoomFree.h"
#include "IGraphicsCurve3d.h"
//几何
#include "IPolyCurve.h"
#include "IPolyCurve3d.h"
#include "IPolygon.h"
#include "GmBodyBuilder.h"
#include "IPlane.h"
#include "ILine3d.h"
#include "IBody.h"

//图元交互事件注册
#include "InteractionEventHandlerRegisterHelper.h"
#include "EventHandler/GeneralCommandInteractionEventHandler.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace Sample;

    IMPLEMENT_REGEN_FUNCTIONS(Sample, WallTag, ReferenceLineDir)
        DBOBJECT_DATA_DEFINE(WallTag)
    {
        SetOwnerElement(nullptr);
        SetName__(L"test");
    }
    UniIdentity WallTag::GetImplementationUid()
    {
        static UniIdentity s_catogryUid = UniIdentity::Create(GuidUtils::FromString(L"{47BD4037-E25B-472B-B8BE-F763BC0A4CB1}"), L"Walld");
        return s_catogryUid;
    }

    bool WallTag::SetOwnerElement(IElement * pOwnerElement)
    {
        if (pOwnerElement == nullptr)
        {
            return true;
        }
        m_OwnerElement = pOwnerElement;
        return true;
    }

    const IElement* WallTag::GetOwnerElement() const
    {
        return GetOwnerElement__();
    }

    IElement* WallTag::GetOwnerElement()
    {
        return GetOwnerElement__();
    }
    gcmp::IDocument* WallTag::GetDocument() const
    {
        if (GetOwnerElement())
            return GetOwnerElement()->GetDocument();
        return nullptr;
    }
    ElementId WallTag::GetOwnerElementId() const
    {
        if (GetOwnerElement())
            return GetOwnerElement()->GetElementId();
        return ElementId::InvalidID;
    }
    std::wstring WallTag::GetName() const
    {
        return GetName__();
    }
    void WallTag::SetName(const std::wstring & szName)
    {
        SetName__(szName);
    }
    void WallTag::UpdateForWeakParentDeletion(const std::set<ElementId>&deletedElementIds)
    {
    }
    ElementId WallTag::GetWallId() const
    {
        return GetWallId__();
    }
    bool WallTag::SetWallId(const ElementId & wallId)
    {
        if (wallId == GetWallId())
            return true;
        SetWallId__(wallId);
        return true;
    }

    void WallTag::ReportParents(IElementParentReporter & reporter) const
    {
        const IElement* pElement = GetOwnerElement();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"IElement为空",L"GDMP",L"2023-12-30");
        reporter.ReportStrong(pElement->GetElementId());
        const IElementBasicInformation* pElementBasicInformation = pElement->GetBasicInformation();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElementBasicInformation, L"IElementBasicInformation为空",L"GDMP",L"2023-12-30");
        reporter.ReportStrong(pElementBasicInformation->GetTypeId());
        const IElementModelShape* pElementModelShape = pElement->GetElementModelShape();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElementModelShape, L"IElementModelShape为空",L"GDMP",L"2023-12-30");
        const gcmp::IGraphicsElementShape* pGraphicsElementShape = pElementModelShape->GetGraphicsElementShape();
        if (pGraphicsElementShape)
        {
            std::vector<ElementId> ids;
            pGraphicsElementShape->GetReferencedElementIds(ids);
            reporter.ReportWeak(ids);
        }
        reporter.ReportStrong(GetWallId());
    }

    bool WallTag::FinishEditing()
    {
        return true;
    }

    WallTag* WallTag::Create(IDocument * pDoc, ElementCreationOptions eco /*= ElementCreationOptions::Normal*/)
    {
        OwnerPtr<WallTag> opWallTag = NEW_AS_OWNER_PTR(WallTag);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opWallTag, L"创建WallTag失败",L"GDMP",L"2023-12-30");
        IGenericElement* pGenericElement = IGenericElement::Create(pDoc, TransferOwnership(opWallTag), WallTag::GetClassId().GetGuid(), eco);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"创建IGenericElement失败",L"GDMP",L"2023-12-30");
        //设置类别
        IElementBasicInformation* pElementBasicInformation = pGenericElement->GetBasicInformation();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementBasicInformation, L"IElementBasicInformation为空",L"GDMP",L"2023-12-30");
        pElementBasicInformation->SetCategoryUid(Sample::WALLTAG_CATEGORY);
        //设置关联更新组件
        pGenericElement->SetElementRegenerationComponent(NEW_AS_OWNER_PTR(WallTagRegenerationComponent));
        //设置控制点信息
        pGenericElement->SetPositionPoints(NEW_AS_OWNER_PTR(WallTagPositionPoints));
        //夹点绑定
        pElementBasicInformation->SetImplementationUid(GetImplementationUid());

        WallTag* pWallTag = quick_cast<WallTag>(pGenericElement->GetExternalObject());
        return pWallTag;
    }

    WallTag* WallTag::Create(IDocument * pDoc, const gcmp::Vector3d & referenceLineDir, gcmp::ElementId wallId, ElementCreationOptions eco /*= ElementCreationOptions::Normal*/)
    {
        WallTag* pWallTag = Create(pDoc, eco);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWallTag, L"创建WallTag失败",L"GDMP",L"2023-12-30");
        pWallTag->SetWallId(wallId);
        pWallTag->SetReferenceLineDir(referenceLineDir);
        pWallTag->MarkReferenceLineDirRdId();
        return pWallTag;
    }
    gcmp::Vector3d WallTag::GetReferenceLineStartPoint() const
    {
        Vector3d referenceLineStartPoint = Vector3d(0, 0, 0);
        IDocument* pDocument = GetDocument();
        DBG_WARN_AND_RETURN_UNLESS(pDocument, referenceLineStartPoint, L"获取Document失败",L"GDMP",L"2023-12-30");
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pDocument->GetElement(GetWallId()));
        DBG_WARN_AND_RETURN_UNLESS(pGenericElement, referenceLineStartPoint, L"获取GenericElement失败",L"GDMP",L"2023-12-30");
        Wall* pWall = quick_cast<Wall>(pGenericElement->GetExternalObject());
        DBG_WARN_AND_RETURN_UNLESS(pWall, referenceLineStartPoint, L"获取Wall失败",L"GDMP",L"2023-12-30");
        WallData* pWallData = pWall->GetData();
        DBG_WARN_AND_RETURN_UNLESS(pWallData, referenceLineStartPoint, L"获取Wall失败",L"GDMP",L"2023-12-30");
        Vector3d wallStartPoint = pWallData->GetStartPoint();
        Vector3d wallEndPoint = pWallData->GetEndPoint();
        referenceLineStartPoint = (wallStartPoint + wallEndPoint) / 2 + Vector3d(0, 0, pWallData->GetHeight());
        return referenceLineStartPoint;
    }

    gcmp::OwnerPtr<gcmp::IGraphicsElementShape>  WallTag::CreateGraphicsElementShape()
    {
        IDocument* pDocument = GetDocument();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDocument, L"获取Document失败",L"GDMP",L"2023-12-30");
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pDocument->GetElement(GetWallId()));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"获取GenericElement失败",L"GDMP",L"2023-12-30");
        Wall* pWall = quick_cast<Wall>(pGenericElement->GetExternalObject());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWall, L"获取Wall失败",L"GDMP",L"2023-12-30");
        WallData* pWallData = pWall->GetData();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWallData, L"获取WallData失败",L"GDMP",L"2023-12-30");
        Vector3d wallStartPoint = pWallData->GetStartPoint();
        Vector3d wallEndPoint = pWallData->GetEndPoint();
        Vector3d wallDir = wallEndPoint - wallStartPoint;
        Vector3d wallNormal = wallDir.Cross(Vector3d::UnitZ);
        wallNormal.Normalize();
        wallDir.Normalize();
        OwnerPtr<gcmp::IGraphicsElementShape> opGraphicsElementShape = IGraphicsElementShape::Create(GraphicsRenderLayer::Model);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGraphicsElementShape, L"GraphicsElementShape创建失败",L"GDMP",L"2023-12-30");
        //箭头
        std::vector<Vector2d> points;
        points.emplace_back(Vector2d(0, 0));
        points.emplace_back(Vector2d(30, 100));
        points.emplace_back(Vector2d(-30, 100));
        points.emplace_back(Vector2d(0, 0));
        OwnerPtr<IPolyCurve> opPolyCurve = IPolyCurve::Create(points);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPolyCurve, L"创建PolyCurve失败",L"GDMP",L"2023-12-30");
        OwnerPtr<IPolygon> opExtrudePolygon = IPolygon::Create();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opExtrudePolygon, L"创建Polygon失败",L"GDMP",L"2023-12-30");
        opExtrudePolygon->AddPolyCurveByClone(opPolyCurve.get());
        Vector3d referenceLineStartPoint = GetReferenceLineStartPoint();
        Vector3d referenceLineEndPoint = GetReferenceLineStartPoint() + GetReferenceLineDir();
        Vector3d referenceLineDir = referenceLineEndPoint - referenceLineStartPoint;
        Vector3d coordx = wallNormal.Cross(referenceLineDir).IsZero() ? wallDir.Cross(referenceLineDir) : wallNormal.Cross(referenceLineDir);
        Coordinate3d coord(referenceLineStartPoint, coordx, referenceLineDir);
        OwnerPtr<IBody> opArrowBody = GmBodyBuilder::CreateExtrudeBody(coord, opExtrudePolygon.get(), coordx.Cross(referenceLineDir), 0, 1);
        OwnerPtr<IGraphicsBRepBody> opArrowGraphicsBRepBody = IGraphicsBRepBody::Create(TransferOwnership(opArrowBody));
        opGraphicsElementShape->AddChild(TransferOwnership(opArrowGraphicsBRepBody));
        //墙的属性信息：文字
        double height = pWallData->GetHeight();
        double width = pWallData->GetWidth();
        double length = (pWallData->GetEndPoint() - pWallData->GetStartPoint()).Length();
        float textSize = 10;
        referenceLineDir.Normalize();
        Vector3d pos(0, 0, 0);
        std::wstring content = L"名称：" + pWall->GetName() + L"\n" + L"高度：" + StringUtil::ToWString(height, 2) + L"\n" + L"宽度：" + StringUtil::ToWString(width, 2) + L"\n" + L"长度：" + StringUtil::ToWString(length, 2);
        OwnerPtr<IGraphicsText> opContentText = IGraphicsText::Create(L"", pos, Vector3d::UnitX, Vector3d::UnitZ, textSize, content, AnchorAlignmentType::LeftBottom);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opContentText, L"opContentText创建失败",L"GDMP",L"2023-12-30");
        gcmp::OwnerPtr<IGraphicsNodeGroup> opGroup = IGraphicsNodeGroup::Create();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGroup, L"opGroup创建失败",L"GDMP",L"2023-12-30");
        opGroup->AddChild(TransferOwnership(opContentText));
        gcmp::OwnerPtr<IGraphicsZoomFree> opzoomFree = IGraphicsZoomFree::Create();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opzoomFree, L"opzoomFree创建失败",L"GDMP",L"2023-12-30");
        opzoomFree->SetCoordinate(gcmp::Coordinate3d(referenceLineEndPoint, gcmp::Vector3d::NegaUnitZ));
        opzoomFree->SetIsFaceUpward(EnZoomFreeSubType::Text, true);
        opzoomFree->AddChild(TransferOwnership(opGroup));
        opzoomFree->SetVisibility(GraphicsNodeVisibility::Always);
        opGraphicsElementShape->AddChild(TransferOwnership(opzoomFree));

        //引导线+分隔线
        OwnerPtr<IGraphicsCurve3d> opGraphicsReferenceLine = IGraphicsCurve3d::Create(ILine3d::Create(referenceLineStartPoint + 100 * referenceLineDir, referenceLineStartPoint + GetReferenceLineDir()).get());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGraphicsReferenceLine, L"opGraphicsReferenceLine创建失败",L"GDMP",L"2023-12-30");
        opGraphicsElementShape->AddChild(TransferOwnership(opGraphicsReferenceLine));
        gcmp::OwnerPtr<IGraphicsNodeGroup> opGroup1 = IGraphicsNodeGroup::Create();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGroup1, L"opGroup1创建失败",L"GDMP",L"2023-12-30");
        std::vector<Vector2d> profilePoints;
        profilePoints.reserve(2);
        profilePoints.emplace_back(Vector2d(0, 65));
        profilePoints.emplace_back(Vector2d(0, 0));
        OwnerPtr<IPolyCurve> opPolyCurve1 = IPolyCurve::Create(profilePoints);
        OwnerPtr<IPlane> opPlane = IPlane::Create(pos, Vector3d::UnitX, Vector3d::UnitY);
        OwnerPtr<IGraphicsPolyCurve> opGPolyCurve = IGraphicsPolyCurve::Create(opPolyCurve1.get(), opPlane.get());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGPolyCurve, L"opGPolyCurve创建失败",L"GDMP",L"2023-12-30");
        opGroup1->AddChild(TransferOwnership(opGPolyCurve));
        double lineSpace = 15.5;
        for (int i = 0; i < 4; i++)
        {
            profilePoints.clear();
            profilePoints.emplace_back(Vector2d(0, i * lineSpace));
            profilePoints.emplace_back(Vector2d(100, i * lineSpace));
            OwnerPtr<IPolyCurve> opPolyCurve2 = IPolyCurve::Create(profilePoints);
            OwnerPtr<IGraphicsPolyCurve> opGPolyCurve2 = IGraphicsPolyCurve::Create(opPolyCurve2.get(), opPlane.get());
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGPolyCurve2, L"opGPolyCurve2创建失败",L"GDMP",L"2023-12-30");
            opGroup1->AddChild(TransferOwnership(opGPolyCurve2));
        }
        gcmp::OwnerPtr<IGraphicsZoomFree> opzoomFree1 = IGraphicsZoomFree::Create();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opzoomFree1, L"opzoomFree1创建失败",L"GDMP",L"2023-12-30");
        opzoomFree1->SetCoordinate(gcmp::Coordinate3d(referenceLineEndPoint, gcmp::Vector3d::NegaUnitZ));
        opzoomFree1->SetIsFaceUpward(EnZoomFreeSubType::Curve2d, true);
        opzoomFree1->AddChild(TransferOwnership(opGroup1));
        opzoomFree1->SetVisibility(GraphicsNodeVisibility::Always);
        opGraphicsElementShape->AddChild(TransferOwnership(opzoomFree1));
        opGraphicsElementShape->SetIsSelectable(true);
        opGraphicsElementShape->SetIsSnappable(true);
        return TransferOwnership(opGraphicsElementShape);
    }

    REGISTER_INTERACTION_EVENT_HANDLER(WallTag, GeneralCommandInteractionEventHandler,
        ICommandInteractionEventArgs);